package com.markhsiu.httpserver.event;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.fileupload.FileUploadException;

import com.markhsiu.common.ConstantUtil;
import com.markhsiu.common.memory.ByteArray;
import com.markhsiu.httpserver.event.formparse.ComonFormParse;
import com.markhsiu.httpserver.event.formparse.FileFormItem;
import com.markhsiu.httpserver.event.formparse.MarkFileUpload;

/**
 * GET /hello?a=1 HTTP/1.1
 * Host: www.markhsiu.com
 * User-agent: Mozilla/4.0
 * Connection: close
 * Accept-language: zh
 * Content-Length: 1024
 * 
 * data........
 * 
 * @author Mark Hsiu
 *
 */
public class Request extends HttpProtocol {
	
	private InputStream input;
	private String url;
	private HttpMethod method;
	private String version;

	private Map<String, String> headers = new HashMap<String, String>();
	private Map<String, String> params = new HashMap<String, String>();
	private List<FileFormItem> files ;
	private boolean hasFile = false;
	
	public Request(InputStream in) {
		input = in;
	}

	public Request load() throws FileUploadException, IOException {
		System.out.println(" ============================== headers ..... ");
		readHeader();
		System.out.println(" ============================== headers ..... ");
		// 不处理get已经post的body为空的情况
		if (getContentLength() > 0) {
			parseBody();
		}

		return this;
	}

	private void parseBody() throws FileUploadException, IOException {

		if (getContentType().startsWith(MULTIPART)) {
			files = new ArrayList<>();
			
//			FileFormParse parse = new FileFormParse(this).execute();
//			params.putAll(parse.getResult());
//			files = parse.getfiles();
			
			MarkFileUpload uploader = new MarkFileUpload();
			List<FileFormItem> list = uploader.parseRequest(this);
			for (FileFormItem fileFormItem : list) {
				if(fileFormItem.isFileField()){
					files.add(fileFormItem);
				} else {
					params.put(fileFormItem.getFeildName(), 
							ConstantUtil.bytesUTF(fileFormItem.getBody()));
				}
			}
			
			if(files != null && files.size() > 0){
				hasFile = true;
			}
		} else {
			ComonFormParse parse = new ComonFormParse(this).execute();
			params.putAll(parse.getResult());
		}
		System.out.println(" ..... params ..... ");
		System.out.println(params);
	}

	
	private void parseUri(String uri) {
		url = uri;
		int index = uri.indexOf("?");
		if (index > 0) {
			parseParam(url.substring(index + 1));
			url = url.substring(0, index);
		}
	}

	private void parseParam(String paramStr) {
		String[] paramArray = paramStr.split("&");
		try {
			for (String param : paramArray) {
				if (param.length() > 1) {
					String[] ps = param.split("=");
					params.put(ps[0], ps.length > 1 ? ConstantUtil.decodeUTF(ps[1]) : "");
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	} 

	public InputStream getInputStream(){
		return input;
	}
	
	public String uri() {
		return url;
	}

	public String version() {
		return version;
	}

	public HttpMethod method() {
		return method;
	}
	
	public boolean hasfile() {
		return hasFile;
	}
	
	public List<FileFormItem> files() {
		return files;
	}

	
	public Map<String, String> params() {
		return params;
	}


	public String getCharacterEncoding() {
        return ConstantUtil.Encoding;
    }

    public String getContentType() {
    	String contentType = this.headers.get(CONTENT_TYPE); 
        return contentType == null ? "" : contentType;
    }

    public long getContentLength() {
    	String contentLength = headers.get(CONTENT_LENGTH); 
        return contentLength == null ? -1L : Long.parseLong(headers.get(CONTENT_LENGTH));
    }

	private void readHeader() throws IOException {
		ByteArray bytes = new ByteArray();
		try {
			int BUFF_SIZE = 2;
			byte[] buff = new byte[BUFF_SIZE];
			int rc = 0;
			int index = -1;
			while (true) {
				rc = input.read(buff, 0, BUFF_SIZE);
				bytes.write(buff, 0, rc);
				if (rc < BUFF_SIZE) {
					break;
				}
				index += rc;
				/*
				 * 13|10
				 * 13|10
				 * 
				 * 48|13
				 * 10|13
				 * 10|56
				 * 
				 */
				if(bytes.read(index-1) == CRLF[0] && bytes.read(index) == CRLF[1]){
					if(bytes.read(index-3) == CRLF[0] && bytes.read(index-2) == CRLF[1]){
						break;
					}
					continue;
				}
				
				if(bytes.read(index-1) == LFCR[0] && bytes.read(index) == LFCR[1]){
					if(bytes.read(index-2) == LFCR[1]){
						rc = input.read(buff, 0, 1);
						bytes.write(buff, 0, rc);
						break;
					}
				}
			}
		} catch (IOException ee) {
			ee.printStackTrace();
		}
		
		parseHeader(bytes.toByteArray());
	}

	
	private void parseHeader(byte[] data){
		String lineInput;
		int lineNumber = 0;
		StringBuilder lineS = new StringBuilder(32);
		
		int length = data.length;
		for (int i = 0; i < length; i++) {
			if(CRLF[0] == data[i]){
				if(CRLF[1] == data[i+1]){
					lineNumber++;
					lineInput = lineS.toString();
					
					if(lineNumber == 1){
						String[] protocol = lineInput.split(" ");
						method = HttpMethod.toValue(protocol[0]);
						parseUri(protocol[1].substring(1));
						version = protocol[2];
					} else {
						if(lineInput.length() < 2){
							break;
						}
						int index = lineInput.indexOf(":");
						headers.put(lineInput.substring(0, index), lineInput.substring(index + 1).trim());
					}
					
					System.out.println(lineInput);
					i++;
					lineS.setLength(0);
					continue;
				}	
			}	
			lineS.append((char)data[i]);
		}		
	}
}
